#include "StdAfx.h"
#include "Clipboard.h"

#define MAX_CONTENT 50
#define PARSE_BIAS 20

CClipboard::CClipboard(void)
{
}

CClipboard::~CClipboard(void)
{
}

BOOL CClipboard::Copy(CClipboard::CShapeList &selectedList,HWND hWnd)
{
	UINT format = RegisterClipboardFormat(_T("CF_SHAPE"));

	if (!OpenClipboard(hWnd))
	{
		AfxMessageBox(_T("Cannot open the clipboard"),0,0);
		return FALSE;
	}

	if(!EmptyClipboard())
	{
		AfxMessageBox(_T("Cannot empty the clipboard"),0,0);
		return FALSE;
	}

	long listSize = getListSize(selectedList);
	HGLOBAL memBlock = GlobalAlloc(GMEM_DDESHARE,listSize + sizeof(long));
	BYTE* pBuffer = (BYTE*)GlobalLock(memBlock);

	long uBias = long(0);
	long listNum = selectedList.size();
	BYTE* pListNum = pBuffer + uBias;
	memcpy(pListNum,&listNum,sizeof(long));
	uBias += sizeof(long);

	
	for (CShapeListItr shapeListItr = selectedList.begin();shapeListItr != selectedList.end();shapeListItr++)
	{
		CopyTree((*shapeListItr),pBuffer,uBias);
	}

	GlobalUnlock(memBlock);
	SetClipboardData(format,memBlock);
	CloseClipboard();

	return TRUE;
}

void CClipboard::CopyTree(CShapeObject* pNode,BYTE* buffer,long& bias)
{
	Shape_Type eShapeType;
	switch(pNode->getType())
	{
	case ST_RECTANGLE:
		{
			eShapeType = ST_RECTANGLE;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			RectData rectData;
			CRectangle* pRect = (CRectangle*)pNode;
			rectData.startPoint = pRect->getLeftTopPoint();
			rectData.endPoint = pRect->getRightBottomPoint();				
			BYTE* pRectData = buffer + bias;
			memcpy(pRectData,&rectData,sizeof(RectData));
			bias += sizeof(RectData);
			break;				
		}
	case ST_DIAMOND:
		{
			eShapeType = ST_DIAMOND;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			DiamData diamData;
			CDiamond* pDiam = (CDiamond*)pNode;
			diamData.startPoint = pDiam->getLeftTopPoint();
			diamData.endPoint = pDiam->getRightBottomPoint();				
			BYTE* pDiamData = buffer + bias;
			memcpy(pDiamData,&diamData,sizeof(RectData));
			bias += sizeof(DiamData);
			break;
		}
	case ST_ARROW:
		{
			eShapeType = ST_ARROW;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			ArrowData arrowData;
			CArrow* pArrow = (CArrow*)pNode;
			arrowData.startPoint = pArrow->getStartPoint().getPosition();
			arrowData.endPoint = pArrow->getEndedPoint().getPosition();					
			BYTE* pArrowData = buffer + bias;
			memcpy(pArrowData,&arrowData,sizeof(ArrowData));
			bias += sizeof(ArrowData);
			break;
		}
	case ST_TEXT:
		{
			eShapeType = ST_TEXT;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			TextData textData;
			CText* text = (CText*)pNode;
			textData.startPoint = text->getLeftTopPoint();
			textData.endPoint = text->getRightBottomPoint();
			textData.textFont = text->getTextInfo().getTextFont();
			textData.textLineNum = text->getTextInfo().getTextContent().size();				
			BYTE* pTextData = buffer + bias;
			memcpy(pTextData,&textData,sizeof(TextData));
			bias += sizeof(TextData);
			TCHAR textContent[MAX_CONTENT];				
			for (long i = 0; i < text->getTextInfo().getTextContent().size(); i++)					
			{
				lstrcpy(textContent,text->getTextInfo().getTextContent()[i]);
				BYTE* pTextContent = buffer + bias;
				memcpy(pTextContent,textContent,MAX_CONTENT * sizeof(TCHAR));
				bias += MAX_CONTENT * sizeof(TCHAR);
			}	

			break;
		}
	default:
		{
			break;
		}
	}	
	long listNum = pNode->getChildList().size();
	BYTE* pListNum = buffer + bias;
	memcpy(pListNum,&listNum,sizeof(long));
	bias += sizeof(long);

	for (CShapeListItr shapeListItr = pNode->getChildList().begin();
		shapeListItr != pNode->getChildList().end();
		shapeListItr++)
	{
		CopyTree((*shapeListItr),buffer,bias);
	}
}

void CClipboard::CutTree(CShapeObject* pNode,BYTE* buffer,long& bias)
{
	Shape_Type eShapeType;	
	switch(pNode->getType())
	{
	case ST_RECTANGLE:
		{
			eShapeType = ST_RECTANGLE;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			RectData rectData;
			CRectangle* pRect = (CRectangle*)pNode;
			rectData.startPoint = pRect->getLeftTopPoint();
			rectData.endPoint = pRect->getRightBottomPoint();				
			BYTE* pRectData = buffer + bias;
			memcpy(pRectData,&rectData,sizeof(RectData));
			bias += sizeof(RectData);
			break;				
		}
	case ST_DIAMOND:
		{
			eShapeType = ST_DIAMOND;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			DiamData diamData;
			CDiamond* pDiam = (CDiamond*)pNode;
			diamData.startPoint = pDiam->getLeftTopPoint();
			diamData.endPoint = pDiam->getRightBottomPoint();				
			BYTE* pDiamData = buffer + bias;
			memcpy(pDiamData,&diamData,sizeof(RectData));
			bias += sizeof(DiamData);
			break;
		}
	case ST_ARROW:
		{
			eShapeType = ST_ARROW;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			ArrowData arrowData;
			CArrow* pArrow = (CArrow*)pNode;
			arrowData.startPoint = pArrow->getStartPoint().getPosition();
			arrowData.endPoint = pArrow->getEndedPoint().getPosition();					
			BYTE* pArrowData = buffer + bias;
			memcpy(pArrowData,&arrowData,sizeof(ArrowData));
			bias += sizeof(ArrowData);
			break;
		}
	case ST_TEXT:
		{
			eShapeType = ST_TEXT;
			BYTE* pShapeType = buffer + bias;
			memcpy(pShapeType,&eShapeType,sizeof(Shape_Type));
			bias += sizeof(Shape_Type);
			TextData textData;
			CText* text = (CText*)pNode;
			textData.startPoint = text->getLeftTopPoint();
			textData.endPoint = text->getRightBottomPoint();
			textData.textFont = text->getTextInfo().getTextFont();
			textData.textLineNum = text->getTextInfo().getTextContent().size();				
			BYTE* pTextData = buffer + bias;
			memcpy(pTextData,&textData,sizeof(TextData));
			bias += sizeof(TextData);
			TCHAR textContent[MAX_CONTENT];				
			for (long i = 0; i < text->getTextInfo().getTextContent().size(); i++)					
			{
				lstrcpy(textContent,text->getTextInfo().getTextContent()[i]);
				BYTE* pTextContent = buffer + bias;
				memcpy(pTextContent,textContent,MAX_CONTENT * sizeof(TCHAR));
				bias += MAX_CONTENT * sizeof(TCHAR);
			}	

			break;
		}
	default:
		{
			break;
		}
	}	
	pNode->disappear();
	long listNum = pNode->getChildList().size();
	BYTE* pListNum = buffer + bias;
	memcpy(pListNum,&listNum,sizeof(long));
	bias += sizeof(long);

	for (CShapeListItr shapeListItr = pNode->getChildList().begin();
		shapeListItr != pNode->getChildList().end();
		shapeListItr++)
	{
		CopyTree((*shapeListItr),buffer,bias);
	}
}

BOOL CClipboard::Cut(CShapeList& selectedList,HWND hWnd)
{
	UINT format = RegisterClipboardFormat(_T("CF_SHAPE"));

	if (!OpenClipboard(hWnd))
	{
		AfxMessageBox(_T("Cannot open the clipboard"),0,0);
		return FALSE;
	}

	if(!EmptyClipboard())
	{
		AfxMessageBox(_T("Cannot empty the clipboard"),0,0);
		return FALSE;
	}

	long listSize = getListSize(selectedList);
	HGLOBAL memBlock = GlobalAlloc(GMEM_DDESHARE,listSize + sizeof(long));
	BYTE* pBuffer = (BYTE*)GlobalLock(memBlock);

	long uBias = long(0);
	long listNum = selectedList.size();
	BYTE* pListNum = pBuffer + uBias;
	memcpy(pListNum,&listNum,sizeof(long));
	uBias += sizeof(long);


	for (CShapeListItr shapeListItr = selectedList.begin();shapeListItr != selectedList.end();shapeListItr++)
	{
		CutTree((*shapeListItr),pBuffer,uBias);
		/************************************************************************/
		CUndo::SaveOperation(*shapeListItr, OT_DELETE, NULL);
		/************************************************************************/
	}
	/************************************************************************/
	CUndo::endOperation();
	/************************************************************************/

	GlobalUnlock(memBlock);
	SetClipboardData(format,memBlock);
	CloseClipboard();

	return TRUE;	
}

BOOL CClipboard::Parse(HWND hWnd)
{
	UINT format = RegisterClipboardFormat(_T("CF_SHAPE"));
	CShapeObject* pRootShape = CUnitManager::getRootShape();	

	if (!OpenClipboard(hWnd))
	{
		AfxMessageBox(_T("Cannot open the clipboard"),0,0);
		return FALSE;
	}
	
	HANDLE hData = GetClipboardData(format);
	if (hData != NULL)
	{
		long listSize;	
		long lBias = 0;

		BYTE* pData = (BYTE*)GlobalLock(hData);

		long* plistSize = (long*)pData;
		memcpy(&listSize,plistSize,sizeof(long));
		lBias += sizeof(long);

		
		for (long i = 0; i < listSize; i++)
		{
			ParseTree(pRootShape,pData,lBias);		
		}
		/************************************************************************/
		CUndo::endOperation();
		/************************************************************************/
	}

	CUnitManager::setArrowNodeRelation(pRootShape);
	
	GlobalUnlock(hData);
	CloseClipboard();
	
	return TRUE;
}

void CClipboard::ParseTree(CShapeObject* pNode,BYTE* data,long& bias)
{
	CShapeObject* currentNode = pNode;
	Shape_Type eShapeType;
	BYTE* pShapeType = data + bias;
	memcpy(&eShapeType,pShapeType,sizeof(Shape_Type));
	bias += sizeof(Shape_Type);
	switch(eShapeType)
	{
	case ST_RECTANGLE:
		{						
			RectData rectData;				
			BYTE* pRectData = data + bias;
			memcpy(&rectData,pRectData,sizeof(RectData));
			bias += sizeof(RectData);
			CRectangle* rect = new CRectangle(CPoint(rectData.startPoint.x + PARSE_BIAS,rectData.startPoint.y + PARSE_BIAS),
				CPoint(rectData.endPoint.x + PARSE_BIAS,rectData.endPoint.y + PARSE_BIAS));	
			rect->attach(pNode);
			/************************************************************************/
			if (rect->isKindOf(ST_NODE))
			{
				createParameter*		ptrParameter = new createParameter;
				CNode*	ptrNode = (CNode*)rect;
				ptrParameter->topleft = ptrNode->getLeftTopPoint();
				ptrParameter->bottomright = ptrNode->getRightBottomPoint();
				CUndo::SaveOperation(ptrNode, OT_CREATE, ptrParameter);
			}
			/************************************************************************/
			currentNode = rect;
			break;				
		}
	case ST_DIAMOND:
		{
			DiamData diamData;				
			BYTE* pDiamData = data + bias;
			memcpy(&diamData,pDiamData,sizeof(DiamData));
			bias += sizeof(DiamData);
			CDiamond* diam = new CDiamond(CPoint(diamData.startPoint.x + PARSE_BIAS,diamData.startPoint.y + PARSE_BIAS),
				CPoint(diamData.endPoint.x + PARSE_BIAS,diamData.endPoint.y + PARSE_BIAS));	
			diam->attach(pNode);
			/************************************************************************/
			if (diam->isKindOf(ST_NODE))
			{
				createParameter*		ptrParameter = new createParameter;
				CNode*	ptrNode = (CNode*)diam;
				ptrParameter->topleft = ptrNode->getLeftTopPoint();
				ptrParameter->bottomright = ptrNode->getRightBottomPoint();
				CUndo::SaveOperation(ptrNode, OT_CREATE, ptrParameter);
			}
			/************************************************************************/
			currentNode = diam;
			break;	
		}
	case ST_ARROW:
		{
			ArrowData arrowData;
			BYTE* pArrowData = data + bias;
			memcpy(&arrowData,pArrowData,sizeof(ArrowData));
			bias += sizeof(ArrowData);
			CArrow* arrow = new CArrow();
			CEndPoint endStartPoint;
			CEndPoint endEndPoint;
			endStartPoint.setPosition(CPoint(arrowData.startPoint.x + PARSE_BIAS,arrowData.startPoint.y + PARSE_BIAS));	
			endEndPoint.setPosition(CPoint(arrowData.endPoint.x + PARSE_BIAS,arrowData.endPoint.y + PARSE_BIAS));	
			arrow->setStartPoint(endStartPoint);
			arrow->setEndedPoint(endEndPoint);
			arrow->getStartPoint().setLineBelongTo(arrow);
			arrow->getEndedPoint().setLineBelongTo(arrow);
			arrow->calTurningPointList();					
			arrow->finishCreated();
			arrow->attach(pNode);	
			currentNode = arrow;
			break;
		}
	case ST_TEXT:
		{
			TextData textData;
			BYTE* pTextData = data + bias;
			memcpy(&textData,pTextData,sizeof(TextData));
			bias += sizeof(TextData);
			CText* text = new CText(CPoint(textData.startPoint.x + PARSE_BIAS,textData.startPoint.y + PARSE_BIAS),
				CPoint(textData.endPoint.x + PARSE_BIAS,textData.endPoint.y + PARSE_BIAS));
			CTextInfo textInfo;
			textInfo.setTextFont(textData.textFont);	

			CString textContent;
			TCHAR cTextContent[MAX_CONTENT];
			for (long i = 0; i < textData.textLineNum; i++)
			{			
				BYTE* pTextContent = data + bias;
				memcpy(&cTextContent,pTextContent,MAX_CONTENT * sizeof(TCHAR));						
				bias += MAX_CONTENT * sizeof(TCHAR);
				textContent.Format(cTextContent);
				textInfo.addTextContentLine(textContent);
			}
			text->setTextInfo(textInfo);
			text->attach(pNode);
			/************************************************************************/
			if (text->isKindOf(ST_NODE))
			{
				createParameter*		ptrParameter = new createParameter;
				CNode*	ptrNode = (CNode*)text;
				ptrParameter->topleft = ptrNode->getLeftTopPoint();
				ptrParameter->bottomright = ptrNode->getRightBottomPoint();
				CUndo::SaveOperation(ptrNode, OT_CREATE, ptrParameter);
			}
			/************************************************************************/
			currentNode = text;
			break;
		}
	default:
		{
			break;
		}
	}	
	long listSize;
	BYTE* plistSize = data + bias;
	memcpy(&listSize,plistSize,sizeof(long));
	bias += sizeof(long);	
	
	for (long i = 0; i < listSize; i++)
	{
		ParseTree(currentNode,data,bias);
	}		
}


long CClipboard::getListSize(CClipboard::CShapeList &selectedList)
{
	long listSize = (long)0;
	
	listSize += sizeof(long);
	for (CShapeListItr shapeListItr = selectedList.begin();shapeListItr != selectedList.end();shapeListItr++)
	{
		listSize += calListSize((*shapeListItr));
	}

	return listSize;	
}

long CClipboard::calListSize(CShapeObject* pNode)
{
	long listSize = 0;
	switch(pNode->getType())
	{
	case ST_RECTANGLE:
		{
			listSize += sizeof(RectData) + sizeof(Shape_Type);
			break;
		}
	case ST_DIAMOND:
		{
			listSize += sizeof(DiamData) + sizeof(Shape_Type);
			break;
		}
	case ST_ARROW:
		{
			listSize += sizeof(ArrowData) + sizeof(Shape_Type);
			break;
		}
	case ST_TEXT:
		{
			listSize += sizeof(TextData) + sizeof(Shape_Type);
			CText* pText = (CText*)(pNode);
			listSize += MAX_CONTENT * sizeof(TCHAR) * pText->getTextInfo().getTextContent().size();
			break;
		}
	default:
		{
			break;
		}			
	}	
	listSize += sizeof(long);
	for (CShapeListItr shapeListItr = pNode->getChildList().begin();
		shapeListItr != pNode->getChildList().end();
		shapeListItr++)
	{
		listSize += calListSize((*shapeListItr));
	}
	return listSize;

}